#include "stdafx.h"
#include "node.h"

namespace octree
{
	/*
	** Send a list of entities to parent node
	*/
	void COCTreeNode::notifyParent_(entity_mask_info * ent_list, unsigned long ent_count)
	{
		debug::toVsConsole("notifyParent_ %s\n", getNodeName_());
		COCTreeNode & parent = getParent();
		unsigned long parent_addr = reinterpret_cast<unsigned long>(&parent);
		COCTreeNode & normalized_parent = *reinterpret_cast<COCTreeNode *>(parent_addr & 0xFFFFFFFE);
		normalized_parent.registerEntities_(ent_list, ent_count, COCTreeManager::getTmpBuff1(), COCTreeManager::getTmpBuff2(), parent_addr & 0x00000001);
	}

	/*
	** Recompute position mask and compare with previous one.
	** If different, erase from node and rellocate
	*/
	void COCTreeNode::update_local_entities_()
	{
		debug::toVsConsole("update_local_entities_ %s\n", getNodeName_());
		entity_mask_info * entities_changed = COCTreeManager::getTmpBuff1();
		unsigned long ec_cnt = 0;

		const __m128 c = center;
		const __m128 c_sz = _mm_load1_ps(&c.m128_f32[0]);					// octant's half-length

		// Mask Extraction
		const unsigned long idx_max = ent_cnt;
		for (unsigned long idx = 0; idx < idx_max; idx++)
		{
			entity_mask_info & emi = entities[idx];
			const CEntity * e = emi.e;
			const __m128 & ent_pos = e->position().getXMM();
			const unsigned long mask = createMask_(c, c_sz, ent_pos);
			
			if (mask != emi.mask) // the state of the entity changed since last update
			{
				emi.mask = mask;
				if ((mask ^ emi.mask) & 0x0000ff00)
				{
					new (entities_changed + ec_cnt) entity_mask_info(emi.e, mask);
					++ec_cnt;
				}
			}
		}

		if (ec_cnt) // something changed ?
		{
			entity_mask_info * emi_start = &entities_changed[0];
			entity_mask_info * emi_end = &entities_changed[ec_cnt - 1];
			entity_mask_info * emi_curr = emi_end;

			while (emi_curr >= emi_start)
			{
				const entity_mask_info & emi = * (emi_curr);
				if (emi.mask & 0x00000f00) // excluded bit set ?
				{
					remove_(emi.e);
					new (emi_curr) entity_mask_info(emi_end->e, emi_end->mask);
					--emi_end;
				}
				--emi_curr;
			}
			notifyParent_(emi_start, ec_cnt);
		}
	}

} // namespace octree